#ifndef __SCLAB_DATA_H__
#define __SCLAB_DATA_H__

////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////

#include <vector>
#include <string>
#include <iostream>
#include <fstream>
#include <deque>
#include "SCProgram.hpp"
#include "SCEngine.hpp"
#include "LabState.hpp"
#include <ctime>

////////////////////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////////////////////

class wxWindow;
class wxToolBar;
class wxStatusBar;

////////////////////////////////////////////////////////////////////////////////
// Namespaces
////////////////////////////////////////////////////////////////////////////////

namespace SC {

////////////////////////////////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////////////////////////////////

class ProgramPanel;
class ProgramStatePanel;
class ExecutionPanel;
class PlaybackPanel;
class UniversePanel;
class SystemsPanel;
class ConsolePanel;
class VisualiserPanel;

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

/// Data of the SCLab application
class SCLabData {

	public:

		/// Default constructor
		SCLabData();

		/// Returns the engine
		SCEngine & Engine() { return this->engine; }

		/// Loads a program from a given file name
		void LoadProgram();

		/// Resets the current program's execution
		void ResetExecution(const bool = true);

		/// Sets a new record (output) stream
		void SetRecordFile(const std::string &);

		/// Sets a new log (inout) stream
		void SetLogFile(const std::string &);

		/// New iterations are run/stopped
		void NewIterationLoop(const bool, const bool = false);

		/// Playback is run/stopped
		void PlaybackLoop(const bool);

		/// Execute a new computation
		void ExecuteNew();

		/// Execute a log recorded computation
		void ExecuteLog();

		/// Modifies the universe
		void ModifyUniverse(const int, const std::string &);

		/// Sets the number of memorised states
		void SetMaxNbMemorisedStates(const unsigned int);

		/// Returns the timer (read-only)
		const unsigned int GetTimer() const { return this->timer; }

		/// Returns the timer
		unsigned int & Timer() { return this->timer; }

		/// Restore previous state
		void RestorePreviousState();

protected:

		/// Program
		SCProgram program;

		/// Engine
		SCEngine engine;

		/// Plugin-ins directories
		std::vector<std::string> plugin_dirs;

		/// Recording (output) stream
		std::ofstream rec_stream;

		/// Log (input) stream
		std::ifstream log_stream;

		/// Previous states buffer
		std::deque<LabState> memorised_lab_states;

		/// Timer (maximum number of computations per second)
		unsigned int timer;

		/// Last computation time
		clock_t last_ctime;

		/// Last execution is a log
		bool last_is_log;

		/// Parent window for child creation
		wxWindow * parent;

		/// Tool bar
		wxToolBar * tool_bar;

		/// Status bar
		wxStatusBar * status_bar;

		/// Panels to update
		ProgramPanel * program_panel;
		ProgramStatePanel * program_state_panel;
		ExecutionPanel * execution_panel;
		PlaybackPanel * playback_panel;
		UniversePanel * universe_panel;
		SystemsPanel * systems_panel;
		ConsolePanel * console_panel;
		VisualiserPanel * visualiser_panel;

		/// Print out on the record stream the given system changes
		void printout_system_changes(const SCSystemChanges &);

		/// Read system changes from the log stream
		void read_system_changes(SC::SCSystemChanges &, std::istream &);

		/// Execute an action if needed and return true if more is needed
		const bool execute_action();

		/// Update the fields impacted by the last iteration
		void update_fields(const bool = true);

		/// Memorises the lab state
		void memorise_lab_state();

};

////////////////////////////////////////////////////////////////////////////////
// Closing Namespaces
////////////////////////////////////////////////////////////////////////////////

}

////////////////////////////////////////////////////////////////////////////////

#endif
